-module(cus_proc_manage).

-include("cus.hrl").
-include("cus_pb.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").

-export([
    start/0,
    user_proc_start/1,
    conversation_proc_start/1
        ]).

-export([
    user_call/2,
    user_cast/2,
    conversation_call/2,
    conversation_cast/2
        ]).


-define(UserProcName, "cus_user_proc_").
-define(ConversationProcName, "cus_conversation_proc_").
-define(NUM, 5000).


start() ->
    user_procs_start(),
    conversation_procs_start(),
    ?INFO_MSG("cus proc manage start success", []).


user_procs_start() ->
    [user_proc_start(N) || N <- lists:seq(1, ?NUM)].


conversation_procs_start() ->
    [conversation_proc_start(N) || N <- lists:seq(1, ?NUM)].


user_proc_start(Idx) ->
    case cus_config:is_business_node() of
        true ->
            start_user_proc(Idx);
        _ ->
            undefined
    end.


conversation_proc_start(Idx) ->
    case cus_config:is_business_node() of
        true ->
            start_conversation_proc(Idx);
        _ ->
            undefined
    end.


user_call(Uid, Msg) ->
    Pid = user_proc(Uid),
    call(Pid, Msg).


user_cast(Uid, Msg) ->
    Pid = user_proc(Uid),
    cast(Pid, Msg).


conversation_call(Cid, Msg) ->
    Pid = conversation_proc(Cid),
    call(Pid, Msg).


conversation_cast(Cid, Msg) ->
    Pid = conversation_proc(Cid),
    cast(Pid, Msg).


user_proc(Uid) ->
    NodeList = cus_config:business_nodes(),
    NodeIdx = erlang:phash(Uid, length(NodeList)),
    NodeName = lists:nth(NodeIdx, NodeList),
    Idx = erlang:phash(Uid, ?NUM),
    ProcName = user_proc_name(atom_to_list(NodeName), Idx),
    case global:whereis_name(ProcName) of
        undefined ->
            case rpc:call(NodeName, cus_proc_manage, user_proc_start, [Idx]) of
                {badrpc, _Reason} ->
                    undefined;
                {error, _Err} ->
                    undefined;
                Pid ->
                    Pid
            end;
        Pid ->
            Pid
    end.


start_user_proc(Idx) ->
    case cus_user:start() of
        {ok, Client} ->
            NodeName = node(),
            ProcName = user_proc_name(atom_to_list(NodeName), Idx),
            global:register_name(ProcName, Client),
            Client;
        {error, _} = Err ->
            Err
    end.


start_conversation_proc(Idx) ->
    case cus_conversation:start() of
        {ok, Client} ->
            NodeName = node(),
            ProcName = conversation_proc_name(atom_to_list(NodeName), Idx),
            global:register_name(ProcName, Client),
            Client;
        {error, _} = Err ->
            Err
    end.


conversation_proc(Cid) ->
    NodeList = cus_config:business_nodes(),
    NodeIdx = erlang:phash(Cid, length(NodeList)),
    NodeName = lists:nth(NodeIdx, NodeList),
    Idx = erlang:phash(Cid, ?NUM),
    ProcName = conversation_proc_name(atom_to_list(NodeName), Idx),
    case global:whereis_name(ProcName) of
        undefined ->
            case rpc:call(NodeName, cus_proc_manage, conversation_proc_start, [Idx]) of
                {badrpc, _Reason} ->
                    undefined;
                {error, _Err} ->
                    undefined;
                Pid ->
                    Pid
            end;
        Pid ->
            Pid
    end.


call(Pid, Msg) ->
    case gen_server:call(Pid, Msg, 60000) of
        {ok, Data} ->
            Data;
        Reason ->
            ?ERROR_MSG("cus proc manage call Pid : ~p, Msg : ~p error reason : ~p~n", [Pid, Msg, Reason]),
            Reason
    end.


cast(Pid, Msg) ->
    gen_server:cast(Pid, Msg).



user_proc_name(NodeName, N) ->
    list_to_atom(NodeName ++ ?UserProcName ++ integer_to_list(N)).


conversation_proc_name(NodeName, N) ->
    list_to_atom(NodeName ++ ?ConversationProcName ++ integer_to_list(N)).